#include "stdafx.h"
//#include "qapp.h"
#include "qtaskdialog.h"


using namespace micro::dialog;


HRESULT CALLBACK micro::dialog::TaskDialogCallback( HWND hWnd,  UINT uNotification,  WPARAM wParam,  LPARAM lParam,  LONG_PTR dwRefData )
{
    QTaskDialog * pTaskDialog = reinterpret_cast<QTaskDialog *>( dwRefData );

    ASSERT( pTaskDialog != nullptr );

    HRESULT hRes = S_OK;

    switch ( uNotification )
    {
        case TDN_BUTTON_CLICKED:
            // wParam = Button ID
            pTaskDialog->m_nButtonId = static_cast<int>( wParam );
            hRes = pTaskDialog->OnCommandControlClick( static_cast<int>( wParam ) );
            break;

        case TDN_HYPERLINK_CLICKED:
            // lParam = (LPCWSTR)pszHREF
            hRes = pTaskDialog->OnHyperlinkClick( QString( reinterpret_cast<LPCWSTR>( lParam ) ) );
            break;

        case TDN_TIMER:
            // wParam = Milliseconds since dialog created or timer reset
            hRes = pTaskDialog->OnTimer( static_cast<long>( wParam ) );
            break;

        case TDN_DESTROYED:
            hRes = pTaskDialog->OnDestroy();
            pTaskDialog->m_hWnd = 0; //disable runtime
            break;

        case TDN_NAVIGATED:
            hRes = pTaskDialog->OnNavigatePage();
            break;

        case TDN_RADIO_BUTTON_CLICKED:
            // wParam = Radio Button ID
            pTaskDialog->m_nRadioId = static_cast<int>( wParam );
            hRes = pTaskDialog->OnRadioButtonClick( static_cast<int>( wParam ) );
            break;

        case TDN_CREATED:
            // Sending TDM_CLICK_BUTTON and TDM_CLICK_RADIO_BUTTON do under OnCreated method.
            hRes = pTaskDialog->OnCreate();
            break;

        case TDN_DIALOG_CONSTRUCTED:
            pTaskDialog->m_hWnd = hWnd;

            if ( pTaskDialog->m_nFlags & TDF_SHOW_PROGRESS_BAR )
            {
                if ( pTaskDialog->m_nFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR )
                {
                    SendMessage( hWnd, TDM_SET_PROGRESS_BAR_MARQUEE,	static_cast<WPARAM>( pTaskDialog->m_nProgressState ),
                                 static_cast<LPARAM>( pTaskDialog->m_nProgressPos ) );
                }
                else
                {
                    SendMessage( hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM( pTaskDialog->m_nProgressRangeMin, pTaskDialog->m_nProgressRangeMax ) );
                    SendMessage( hWnd, TDM_SET_PROGRESS_BAR_POS, static_cast<WPARAM>( pTaskDialog->m_nProgressPos ) , 0 );
                    SendMessage( hWnd, TDM_SET_PROGRESS_BAR_STATE, static_cast<WPARAM>( pTaskDialog->m_nProgressState ), 0 );
                }
            }

            if ( !pTaskDialog->m_aRadioButtons.IsEmpty() )
            {
                INT_PTR nCount = pTaskDialog->m_aRadioButtons.GetSize();

                for ( INT_PTR i = 0; i < nCount; i++ )
                {
                    if ( !( pTaskDialog->m_aRadioButtons[i].cState & QTaskDialog::BUTTON_ENABLED ) )
                    {
                        SendMessage( hWnd, TDM_ENABLE_RADIO_BUTTON,
                                     static_cast<WPARAM>( pTaskDialog->m_aRadioButtons[i].nId ), static_cast<LPARAM>( FALSE ) );
                    }
                }
            }

            if ( !pTaskDialog->m_aButtons.IsEmpty() )
            {
                INT_PTR nCount = pTaskDialog->m_aButtons.GetSize();

                for ( INT_PTR i = 0; i < nCount; i++ )
                {
                    if ( !( pTaskDialog->m_aButtons[i].cState & QTaskDialog::BUTTON_ENABLED ) )
                    {

                        SendMessage( hWnd, TDM_ENABLE_BUTTON,
                                     static_cast<WPARAM>( pTaskDialog->m_aButtons[i].nId ), static_cast<LPARAM>( FALSE ) );
                    }

                    if ( pTaskDialog->m_aButtons[i].cState & QTaskDialog::BUTTON_ELEVATION )
                    {
                        SendMessage( hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE,
                                     static_cast<WPARAM>( pTaskDialog->m_aButtons[i].nId ), static_cast<LPARAM>( TRUE ) );
                    }
                }
            }

            if ( pTaskDialog->m_nButtonDisabled || pTaskDialog->m_nButtonElevation )
            {
                UINT nButtonFlag = TDCBF_OK_BUTTON;

                for ( int i = 0; i < pTaskDialog->GetCommonButtonCount(); i++ )
                {
                    if ( pTaskDialog->m_nButtonDisabled & nButtonFlag )
                    {
                        //Make sure that button id is defined
                        ASSERT( pTaskDialog->GetCommonButtonId( nButtonFlag ) );

                        SendMessage( hWnd, TDM_ENABLE_BUTTON,
                                     static_cast<WPARAM>( pTaskDialog->GetCommonButtonId( nButtonFlag ) ), static_cast<LPARAM>( FALSE ) );
                    }

                    if ( pTaskDialog->m_nButtonElevation & nButtonFlag )
                    {
                        //Make sure that button id is defined
                        ASSERT( pTaskDialog->GetCommonButtonId( nButtonFlag ) );

                        SendMessage( hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE,
                                     static_cast<WPARAM>( pTaskDialog->GetCommonButtonId( nButtonFlag ) ), static_cast<LPARAM>( TRUE ) );
                    }

                    nButtonFlag <<= 1;
                }
            }

            hRes = pTaskDialog->OnInit();
            break;

        case TDN_VERIFICATION_CLICKED:
            // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0
            pTaskDialog->m_bVerified = static_cast<BOOL>( wParam );
            hRes = pTaskDialog->OnVerificationCheckboxClick( static_cast<BOOL>( wParam ) );
            break;

        case TDN_HELP:
            hRes = pTaskDialog->OnHelp();
            break;

        case TDN_EXPANDO_BUTTON_CLICKED:
            // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded)
            hRes = pTaskDialog->OnExpandButtonClick( 0 != wParam ? TRUE : FALSE );
            break;
    }

    return hRes;
}



QTaskDialog::QTaskDialog( const QString & strContent,  const QString & strMainInstruction,  const QString & strTitle,
                          const QString & strFooter, /* = _T("") */
                          int nCommonButtons /* = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON */,
                          int nTaskDialogOptions /* = TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS */ ) :
    m_hWnd( nullptr ), m_nCommonButton( nCommonButtons ), m_nButtonDisabled( 0 ), m_nButtonElevation( 0 ),
    m_nFlags( nTaskDialogOptions ), m_nWidth( 0 ), m_nDefaultCommandControl( 0 ), m_nDefaultRadioButton( 0 ),
    m_strTitle( strTitle ), m_strMainInstruction( strMainInstruction ), m_strContent( strContent ),
    m_strFooter( strFooter ), m_strVerification( _T( "" ) ), m_strInformation( _T( "" ) ),
    m_strExpand( _T( "" ) ), m_strCollapse( _T( "" ) ),
    m_nProgressRangeMin( QTaskDialog::PROGRESS_BAR_MIN ), m_nProgressRangeMax( QTaskDialog::PROGRESS_BAR_MAX ),
    m_nProgressState( PBST_NORMAL ), m_nProgressPos( QTaskDialog::PROGRESS_BAR_MIN ),
    m_bVerified( FALSE ), m_nRadioId( 0 ), m_nButtonId( 0 )
{
    m_mainIcon.pszIcon = nullptr;
    m_footerIcon.pszIcon = nullptr;

    if ( m_nFlags & TDF_VERIFICATION_FLAG_CHECKED )
    {
        m_bVerified = TRUE;
    }
}

QTaskDialog::QTaskDialog( const QString & strContent,  const QString & strMainInstruction,  const QString & strTitle,  const QString & strFooter,
                          int nIDCommandControlsFirst, int nIDCommandControlsLast,  int nCommonButtons,  int nTaskDialogOptions /* = TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS */ ):

    m_hWnd( nullptr ), m_nCommonButton( nCommonButtons ), m_nButtonDisabled( 0 ), m_nButtonElevation( 0 ),
    m_nFlags( nTaskDialogOptions ), m_nWidth( 0 ), m_nDefaultCommandControl( 0 ), m_nDefaultRadioButton( 0 ),
    m_strTitle( strTitle ), m_strMainInstruction( strMainInstruction ), m_strContent( strContent ),
    m_strFooter( strFooter ), m_strVerification( _T( "" ) ), m_strInformation( _T( "" ) ),
    m_strExpand( _T( "" ) ), m_strCollapse( _T( "" ) ),
    m_nProgressRangeMin( QTaskDialog::PROGRESS_BAR_MIN ), m_nProgressRangeMax( QTaskDialog::PROGRESS_BAR_MAX ),
    m_nProgressState( PBST_NORMAL ), m_nProgressPos( QTaskDialog::PROGRESS_BAR_MIN ),
    m_bVerified( FALSE ), m_nRadioId( 0 ), m_nButtonId( 0 )
{
    m_mainIcon.pszIcon = nullptr;
    m_footerIcon.pszIcon = nullptr;

    if ( m_nFlags & TDF_VERIFICATION_FLAG_CHECKED )
    {
        m_bVerified = TRUE;
    }

    LoadCommandControls( nIDCommandControlsFirst, nIDCommandControlsLast );
}

QTaskDialog::~QTaskDialog()
{

}

void QTaskDialog::LoadCommandControls( int nIDCommandControlsFirst,  int nIDCommandControlsLast )
{
    ASSERT( nIDCommandControlsFirst <= nIDCommandControlsLast );
    ASSERT( nIDCommandControlsFirst >= 0 && nIDCommandControlsLast >= 0 );

    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    QString strTmp;
    m_aButtons.RemoveAll();

    for ( int i = nIDCommandControlsFirst; i <= nIDCommandControlsLast; i++ )
    {
        if ( !strTmp.LoadString( i ) )
        {
            continue;
        }

        AddCommandControl( i, strTmp );
    }
}

void QTaskDialog::LoadRadioButtons( int nIDRadioButtonsFirst,  int nIDRadioButtonsLast )
{
    ASSERT( nIDRadioButtonsFirst <= nIDRadioButtonsLast );
    ASSERT( nIDRadioButtonsFirst >= 0 && nIDRadioButtonsLast >= 0 );

    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    QString strTmp;
    m_aRadioButtons.RemoveAll();

    for ( int i = nIDRadioButtonsFirst; i <= nIDRadioButtonsLast; i++ )
    {
        if ( !strTmp.LoadString( i ) )
        {
            continue;
        }

        AddRadioButton( i, strTmp );
    }
}

void QTaskDialog::SetWindowTitle( const QString & strTitle )
{
    m_strTitle = strTitle;

    if ( m_hWnd != nullptr )
    {
        SetWindowText( m_hWnd, m_strTitle );
    }
}

void QTaskDialog::SetMainInstruction( const QString & strMainInstruction )
{
    m_strMainInstruction = strMainInstruction;
    Notify( TDM_SET_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, reinterpret_cast<LPARAM>( ( LPCTSTR ) m_strMainInstruction ) );
}

void QTaskDialog::SetContent( const QString & strContent )
{
    m_strContent = strContent;
    Notify( TDM_SET_ELEMENT_TEXT, TDE_CONTENT, reinterpret_cast<LPARAM>( ( LPCTSTR )m_strContent ) );
}

void QTaskDialog::SetMainIcon( HICON hMainIcon )
{
    ASSERT( hMainIcon != nullptr );

    // If the icon was initially set by HICON, allow only HICON setter method after the window has been created.
    ASSERT( nullptr == m_hWnd || m_nFlags & TDF_USE_HICON_MAIN );

    m_mainIcon.hIcon = hMainIcon;
    m_nFlags |= TDF_USE_HICON_MAIN;

    Notify( TDM_UPDATE_ICON, TDIE_ICON_MAIN, reinterpret_cast<LPARAM>( m_mainIcon.hIcon ) );
}

void QTaskDialog::SetMainIcon( LPCWSTR lpszMainIcon )
{
    ASSERT( lpszMainIcon != nullptr );

    // If the icon was initially set by LPWSTR, allow only LPWSTR setter method after the window has been created.
    ASSERT( nullptr == m_hWnd || !( m_nFlags & TDF_USE_HICON_MAIN ) );

    m_mainIcon.pszIcon = lpszMainIcon;
    m_nFlags &= TDF_USE_HICON_MAIN;

    Notify( TDM_UPDATE_ICON, TDIE_ICON_MAIN, reinterpret_cast<LPARAM>( m_mainIcon.pszIcon ) );
}

void QTaskDialog::SetFooterIcon( HICON hFooterIcon )
{
    ASSERT( hFooterIcon != nullptr );

    // If the icon was initially set by HICON, allow only HICON setter method after the window has been created.
    ASSERT( nullptr == m_hWnd || m_nFlags & TDF_USE_HICON_FOOTER );

    m_footerIcon.hIcon = hFooterIcon;
    m_nFlags |= TDF_USE_HICON_FOOTER;

    Notify( TDM_UPDATE_ICON, TDIE_ICON_FOOTER, reinterpret_cast<LPARAM>( m_footerIcon.hIcon ) );
}

void QTaskDialog::SetFooterIcon( LPCWSTR lpszFooterIcon )
{
    ASSERT( lpszFooterIcon != nullptr );

    // If the icon was initially set by LPWSTR, allow only LPWSTR setter method after the window has been created.
    ASSERT( nullptr == m_hWnd || !( m_nFlags & TDF_USE_HICON_FOOTER ) );

    m_footerIcon.pszIcon = lpszFooterIcon;
    m_nFlags &= ~TDF_USE_HICON_FOOTER;

    Notify( TDM_UPDATE_ICON, TDIE_ICON_FOOTER, reinterpret_cast<LPARAM>( m_footerIcon.pszIcon ) );
}

void QTaskDialog::SetFooterText( const QString & strFooterText )
{
    m_strFooter = strFooterText;
    Notify( TDM_SET_ELEMENT_TEXT, TDE_FOOTER, reinterpret_cast<LPARAM>( ( LPCTSTR )m_strFooter ) );
}

void QTaskDialog::SetVerificationCheckboxText( const QString & strVerificationText )
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_strVerification = strVerificationText;
}

void QTaskDialog::SetExpansionArea( const QString & strExpandedInformation,  const QString & strCollapsedLabel /* = _T("") */,  const QString & strExpandedLabel /* = _T("") */ )
{
    m_strCollapse = strCollapsedLabel;
    m_strExpand = strExpandedLabel;
    m_strInformation = strExpandedInformation;

    Notify( TDM_SET_ELEMENT_TEXT, TDE_EXPANDED_INFORMATION, reinterpret_cast<LPARAM>( ( LPCTSTR )m_strInformation ) );
}

void QTaskDialog::SetDialogWidth( int nWidth /* = 0 */ )
{
    ASSERT( nWidth >= 0 );

    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_nWidth = nWidth;
}

void QTaskDialog::SetCommonButtons( int nButtonMask,  int nDisabledButtonMask /* = 0 */,  int nElevationButtonMask /* = 0 */ )
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_nCommonButton = nButtonMask;

    // Verify disabled command controls
    ASSERT( 0 == nDisabledButtonMask || nButtonMask & nDisabledButtonMask );

    m_nButtonDisabled = nDisabledButtonMask;

    // Verify definiton of elevation
    ASSERT( 0 == nElevationButtonMask || nButtonMask & nElevationButtonMask );

    m_nButtonElevation = nElevationButtonMask;
}

void QTaskDialog::SetCommonButtonOptions( int nDisabledButtonMask,  int nElevationButtonMask /* = 0 */ )
{
    UINT nButtonFlag = TDCBF_OK_BUTTON;

    for ( int i = 0; i < GetCommonButtonCount(); i++ )
    {
        if ( nButtonFlag & m_nCommonButton )
        {
            int nCommonButtonId = GetCommonButtonId( nButtonFlag );
            INT_PTR nCommandCtrlIndex = GetButtonIndex( nCommonButtonId, m_aButtons );

            BOOL bEnabled = nDisabledButtonMask & nButtonFlag ? FALSE : TRUE;
            BOOL bRequiresElevation = nElevationButtonMask & nButtonFlag ? TRUE : FALSE;

            if ( nCommandCtrlIndex != -1 )
            {
                if ( bEnabled )
                {
                    m_aButtons[nCommandCtrlIndex].cState |= QTaskDialog::BUTTON_ENABLED;
                }
                else
                {
                    m_aButtons[nCommandCtrlIndex].cState &= ~QTaskDialog::BUTTON_ENABLED;
                }

                if ( bRequiresElevation )
                {
                    m_aButtons[nCommandCtrlIndex].cState |= QTaskDialog::BUTTON_ELEVATION;
                }
                else
                {
                    m_aButtons[nCommandCtrlIndex].cState &= ~QTaskDialog::BUTTON_ELEVATION;
                }
            }

            Notify( TDM_ENABLE_BUTTON, static_cast<WPARAM>( nCommonButtonId ), static_cast<LPARAM>( bEnabled ) );
            Notify( TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, static_cast<WPARAM>( nCommonButtonId ), static_cast<LPARAM>( bRequiresElevation ) );
        }
        else
        {
            // Don't disable buttons which are not defined
            ASSERT( 0 == nDisabledButtonMask || !( nDisabledButtonMask & nButtonFlag ) );

            // Don't elevate buttons which are not defined
            ASSERT( 0 == nElevationButtonMask || !( nElevationButtonMask & nButtonFlag ) );
        }

        nButtonFlag <<= 1;
    }

    m_nButtonDisabled = nDisabledButtonMask;
    m_nButtonElevation = nElevationButtonMask;
}

void QTaskDialog::AddCommandControl( int nCommandControlID,  const QString & strCaption,  BOOL bEnabled /* = TRUE */,  BOOL bRequiresElevation /* = FALSE */ )
{
    ASSERT( nCommandControlID > 0 );
    ASSERT( !strCaption.IsEmpty() );

    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_aButtons.Add( QTaskDialogButton( nCommandControlID, strCaption,
                                       ( ( bEnabled ? QTaskDialog::BUTTON_ENABLED : 0 ) | ( bRequiresElevation ? QTaskDialog::BUTTON_ELEVATION : 0 ) ) ) );
}

void QTaskDialog::AddRadioButton( int nRadioButtonID,  const QString & strCaption,  BOOL bEnabled /* = TRUE */ )
{
    ASSERT( nRadioButtonID > 0 );
    ASSERT( !strCaption.IsEmpty() );

    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_aRadioButtons.Add( QTaskDialogButton( nRadioButtonID, strCaption, ( bEnabled ? QTaskDialog::BUTTON_ENABLED : 0 ) ) );
}

void QTaskDialog::SetProgressBarRange( int nRangeMin,  int nRangeMax )
{
    ASSERT( nRangeMin < nRangeMax );

    // Progress bar cannot be defined after the window has been created.
    ASSERT( nullptr == m_hWnd || ( !( m_nFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR ) && ( m_nFlags & TDF_SHOW_PROGRESS_BAR ) ) );

    m_nProgressRangeMin = nRangeMin;
    m_nProgressRangeMax = nRangeMax;

    m_nFlags &= ~TDF_SHOW_MARQUEE_PROGRESS_BAR;
    m_nFlags |= TDF_SHOW_PROGRESS_BAR;

    Notify( TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM( m_nProgressRangeMin, m_nProgressRangeMax ) );
}

void QTaskDialog::SetProgressBarPosition( int nProgressPos )
{
    ASSERT( m_nProgressRangeMin <= nProgressPos && nProgressPos <= m_nProgressRangeMax );

    // Progress bar cannot be defined after the window has been created.
    ASSERT( nullptr == m_hWnd || ( !( m_nFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR ) && ( m_nFlags & TDF_SHOW_PROGRESS_BAR ) ) );

    m_nProgressPos = nProgressPos;
    m_nFlags &= ~TDF_SHOW_MARQUEE_PROGRESS_BAR;
    m_nFlags |= TDF_SHOW_PROGRESS_BAR;

    Notify( TDM_SET_PROGRESS_BAR_POS, static_cast<WPARAM>( m_nProgressPos ) , 0 );
}

void QTaskDialog::SetProgressBarState( int nState /* = PBST_NORMAL */ )
{
    //Progress bar cannot be defined after the window has been created.
    ASSERT( nullptr == m_hWnd || ( !( m_nFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR ) && ( m_nFlags & TDF_SHOW_PROGRESS_BAR ) ) );

    m_nProgressState = nState;
    m_nFlags &= ~TDF_SHOW_MARQUEE_PROGRESS_BAR;
    m_nFlags |= TDF_SHOW_PROGRESS_BAR;

    Notify( TDM_SET_PROGRESS_BAR_STATE, static_cast<WPARAM>( m_nProgressState ), 0 );
}

void QTaskDialog::SetProgressBarMarquee( BOOL bEnabled /* = TRUE */,  int nMarqueeSpeed /* = 0 */ )
{
    ASSERT( nMarqueeSpeed >= 0 );

    // Marquee cannot be defined after the window has been created.
    ASSERT( nullptr == m_hWnd || ( ( m_nFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR ) && ( m_nFlags & TDF_SHOW_PROGRESS_BAR ) ) );

    m_nProgressState = bEnabled;
    m_nProgressPos = nMarqueeSpeed;

    m_nFlags |= TDF_SHOW_PROGRESS_BAR | TDF_SHOW_MARQUEE_PROGRESS_BAR;

    Notify( TDM_SET_PROGRESS_BAR_MARQUEE, static_cast<WPARAM>( m_nProgressState ), static_cast<LPARAM>( m_nProgressPos ) );
}

void QTaskDialog::SetOptions( int nOptionFlag )
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_nFlags = nOptionFlag;

    if ( m_nFlags & TDF_VERIFICATION_FLAG_CHECKED )
    {
        m_bVerified = TRUE;
    }
}

int QTaskDialog::GetOptions() const
{
    return m_nFlags;
}

BOOL QTaskDialog::GetVerificationCheckboxState() const
{
    return m_bVerified;
}

int QTaskDialog::GetSelectedRadioButtonID() const
{
    return m_nRadioId;
}

int QTaskDialog::GetSelectedCommandControlID() const
{
    return m_nButtonId;
}

void QTaskDialog::SetCommandControlOptions( int nCommandControlID,  BOOL bEnabled,  BOOL bRequiresElevation /* = FALSE */ )
{
    INT_PTR nIdx = GetButtonIndex( nCommandControlID, m_aButtons );
    ASSERT( nIdx != -1 );

    if ( nIdx != -1 )
    {
        if ( bEnabled )
        {
            m_aButtons[nIdx].cState |= QTaskDialog::BUTTON_ENABLED;
        }
        else
        {
            m_aButtons[nIdx].cState &= ~QTaskDialog::BUTTON_ENABLED;
        }

        if ( bRequiresElevation )
        {
            m_aButtons[nIdx].cState |= QTaskDialog::BUTTON_ELEVATION;
        }
        else
        {
            m_aButtons[nIdx].cState &= ~QTaskDialog::BUTTON_ELEVATION;
        }
    }

    int nButtonFlag = GetCommonButtonFlag( nCommandControlID );

    if ( nButtonFlag != 0 )
    {
        if ( bEnabled )
        {
            m_nButtonDisabled &= ~nButtonFlag;
        }
        else
        {
            m_nButtonDisabled |= nButtonFlag;
        }

        if ( bRequiresElevation )
        {
            m_nButtonElevation |= QTaskDialog::BUTTON_ELEVATION;
        }
        else
        {
            m_nButtonElevation &= ~QTaskDialog::BUTTON_ELEVATION;
        }
    }

    Notify( TDM_ENABLE_BUTTON, static_cast<WPARAM>( nCommandControlID ), static_cast<LPARAM>( bEnabled ) );
    Notify( TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, static_cast<WPARAM>( nCommandControlID ), static_cast<LPARAM>( bRequiresElevation ) );
}

BOOL QTaskDialog::IsCommandControlEnabled( int nCommandControlID ) const
{
    INT_PTR nIdx = GetButtonIndex( nCommandControlID, m_aButtons );
    int nButtonFlag = GetCommonButtonFlag( nCommandControlID );

    ASSERT( nIdx != -1 || nButtonFlag & m_nCommonButton );

    if ( -1 != nIdx )
    {
        return ( m_aButtons[nIdx].cState & QTaskDialog::BUTTON_ENABLED ? TRUE : FALSE );
    }
    else
    {
        return ( m_nButtonDisabled & nButtonFlag ? FALSE : TRUE );
    }
}

void QTaskDialog::ClickCommandControl( int nCommandControlID ) const
{
    ASSERT( GetButtonIndex( nCommandControlID, m_aButtons ) != -1 || GetCommonButtonFlag( nCommandControlID ) & m_nCommonButton );

    Notify( TDM_CLICK_BUTTON, static_cast<WPARAM>( nCommandControlID ) , 0 );
}

void QTaskDialog::SetDefaultCommandControl( int nCommandControlID )
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    ASSERT( GetButtonIndex( nCommandControlID, m_aButtons ) != -1 || GetCommonButtonFlag( nCommandControlID ) & m_nCommonButton );

    m_nDefaultCommandControl = nCommandControlID;
}

void QTaskDialog::RemoveAllCommandControls()
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_aButtons.RemoveAll();
}

void QTaskDialog::SetRadioButtonOptions( int nRadioButtonID,  BOOL bEnabled )
{
    INT_PTR nIdx = GetButtonIndex( nRadioButtonID, m_aRadioButtons );
    ASSERT( nIdx != -1 );

    if ( bEnabled )
    {
        m_aRadioButtons[nIdx].cState |= QTaskDialog::BUTTON_ENABLED;
    }
    else
    {
        m_aRadioButtons[nIdx].cState &= ~QTaskDialog::BUTTON_ENABLED;
    }

    Notify( TDM_ENABLE_RADIO_BUTTON, static_cast<WPARAM>( nRadioButtonID ), static_cast<LPARAM>( bEnabled ) );
}

void QTaskDialog::ClickRadioButton( int nRadioButtonID ) const
{
    ASSERT( GetButtonIndex( nRadioButtonID, m_aRadioButtons ) != -1 );

    Notify( TDM_CLICK_RADIO_BUTTON, static_cast<WPARAM>( nRadioButtonID ), 0 );
}

BOOL QTaskDialog::IsRadioButtonEnabled( int nRadioButtonID ) const
{
    INT_PTR nIdx = GetButtonIndex( nRadioButtonID, m_aRadioButtons );
    ASSERT( nIdx != -1 );

    return ( m_aRadioButtons[nIdx].cState & QTaskDialog::BUTTON_ENABLED ) ? TRUE : FALSE;
}

void QTaskDialog::SetDefaultRadioButton( int nRadioButtonID )
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    ASSERT( GetButtonIndex( nRadioButtonID, m_aRadioButtons ) != -1 );

    m_nDefaultRadioButton = nRadioButtonID;
}

void QTaskDialog::RemoveAllRadioButtons()
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );

    m_aRadioButtons.RemoveAll();
}

void QTaskDialog::SetVerificationCheckbox( BOOL bChecked )
{
    ASSERT( !m_strVerification.IsEmpty() );

    m_bVerified = bChecked;

    if ( m_bVerified )
    {
        m_nFlags |= TDF_VERIFICATION_FLAG_CHECKED;
    }
    else
    {
        m_nFlags &= ~TDF_VERIFICATION_FLAG_CHECKED;
    }

    Notify( TDM_CLICK_VERIFICATION, static_cast<WPARAM>( bChecked ), 0 );
}

// BOOL QTaskDialog::IsSupported()
// {
//     HINSTANCE hInst = ::GetModuleHandleW( L"COMCTL32.DLL" );
//     ASSERT( hInst != nullptr );
//     return( GetProcAddress( hInst, "TaskDialogIndirect" ) != nullptr );
// }

INT_PTR QTaskDialog::ShowDialog( const QString & strContent,  const QString & strMainInstruction,  const QString & strTitle,
                                 int nIDCommandControlsFirst,  int nIDCommandControlsLast,
                                 int nCommonButtons /* = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON */,
                                 int nTaskDialogOptions /* = TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS */,
                                 const QString & strFooter /* = _T("") */ )
{
    QTaskDialog d( strContent, strMainInstruction, strTitle, strFooter, nIDCommandControlsFirst, nIDCommandControlsLast, nCommonButtons, nTaskDialogOptions );

    return d.DoModal();
}


void QTaskDialog::NavigateTo( QTaskDialog & oTaskDialog ) const
{
    TASKDIALOGCONFIG configTaskDialog = {0};

    oTaskDialog.FillStruct( configTaskDialog );
    Notify( TDM_NAVIGATE_PAGE, 0, reinterpret_cast<LPARAM>( &configTaskDialog ) );
    oTaskDialog.FreeStruct( configTaskDialog );
}

void QTaskDialog::FillStruct( _Inout_ TASKDIALOGCONFIG & configTaskDialog )
{
    configTaskDialog.dwCommonButtons = m_nCommonButton;
    configTaskDialog.dwFlags = m_nFlags;

    if ( ( configTaskDialog.dwFlags & ( TDF_USE_COMMAND_LINKS | TDF_USE_COMMAND_LINKS_NO_ICON ) ) && m_aButtons.IsEmpty() )
    {
        configTaskDialog.dwFlags &= ~( TDF_USE_COMMAND_LINKS | TDF_USE_COMMAND_LINKS_NO_ICON );
    }

    // Ensure that there is footer field and we can set the footer icon.
    if ( m_strFooter.IsEmpty() && m_footerIcon.pszIcon != nullptr )
    {
        m_strFooter = _T( " " );
    }

    configTaskDialog.cxWidth = m_nWidth;

    configTaskDialog.nDefaultButton = m_nDefaultCommandControl;
    configTaskDialog.nDefaultRadioButton = m_nDefaultRadioButton;

    configTaskDialog.pszWindowTitle = m_strTitle;
    configTaskDialog.pszMainInstruction = m_strMainInstruction;
    configTaskDialog.pszContent = m_strContent;
    configTaskDialog.pszFooter = m_strFooter;

    configTaskDialog.pszExpandedInformation = m_strInformation;
    configTaskDialog.pszExpandedControlText = m_strExpand;
    configTaskDialog.pszCollapsedControlText = m_strCollapse;

    if ( m_nFlags & TDF_USE_HICON_MAIN )
    {
        configTaskDialog.hMainIcon = m_mainIcon.hIcon;
    }
    else
    {
        configTaskDialog.pszMainIcon = m_mainIcon.pszIcon;
    }

    if ( m_nFlags & TDF_USE_HICON_FOOTER )
    {
        configTaskDialog.hFooterIcon = m_footerIcon.hIcon;
    }
    else
    {
        configTaskDialog.pszFooterIcon = m_footerIcon.pszIcon;
    }

    if ( !m_strVerification.IsEmpty() )
    {
        configTaskDialog.pszVerificationText = m_strVerification ;
    }
    else
    {
        configTaskDialog.dwFlags &= ~TDF_VERIFICATION_FLAG_CHECKED;
        configTaskDialog.pszVerificationText = nullptr;
    }

    if ( !m_aRadioButtons.IsEmpty() )
    {
        configTaskDialog.pRadioButtons = GetButtonData( m_aRadioButtons );
        configTaskDialog.cRadioButtons = static_cast<UINT>( m_aRadioButtons.GetSize() );
    }

    if ( !m_aButtons.IsEmpty() )
    {
        configTaskDialog.pButtons = GetButtonData( m_aButtons );
        configTaskDialog.cButtons = static_cast<UINT>( m_aButtons.GetSize() );
    }

    configTaskDialog.lpCallbackData = reinterpret_cast<LONG_PTR>( this );
    configTaskDialog.pfCallback = TaskDialogCallback;
    configTaskDialog.cbSize = sizeof( TASKDIALOGCONFIG );
}

void QTaskDialog::FreeStruct( _Inout_ TASKDIALOGCONFIG & configTaskDialog )
{
    if ( configTaskDialog.pButtons != nullptr )
    {
        delete [] configTaskDialog.pButtons;
        configTaskDialog.pButtons = nullptr;
    }

    if ( configTaskDialog.pRadioButtons != nullptr )
    {
        delete [] configTaskDialog.pRadioButtons;
        configTaskDialog.pRadioButtons = nullptr;
    }
}


int QTaskDialog::GetCommonButtonId( int nFlag ) const
{
    switch ( nFlag )
    {
        case TDCBF_OK_BUTTON:
            return IDOK;

        case TDCBF_YES_BUTTON:
            return IDYES;

        case TDCBF_NO_BUTTON:
            return IDNO;

        case TDCBF_CANCEL_BUTTON:
            return IDCANCEL;

        case TDCBF_RETRY_BUTTON:
            return IDRETRY;

        case TDCBF_CLOSE_BUTTON:
            return IDCLOSE;

        default:
            return 0;
    }
}

int QTaskDialog::GetCommonButtonFlag( int nButtonId ) const
{
    switch ( nButtonId )
    {
        case IDOK:
            return TDCBF_OK_BUTTON;

        case IDYES:
            return TDCBF_YES_BUTTON;

        case IDNO:
            return TDCBF_NO_BUTTON;

        case IDCANCEL:
            return TDCBF_CANCEL_BUTTON;

        case IDRETRY:
            return TDCBF_RETRY_BUTTON;

        case IDCLOSE:
            return TDCBF_CLOSE_BUTTON;

        default:
            return 0;
    }
}

int QTaskDialog::GetCommonButtonCount() const
{
    //it's the amount of common buttons in commctrl.h
    return 6;
}

INT_PTR QTaskDialog::GetButtonIndex( int nId,  const QTaskDialogButtonArray & oButtonArr ) const
{
    INT_PTR nCount = oButtonArr.GetSize();

    for ( INT_PTR i = 0; i < nCount; i++ )
    {
        if ( oButtonArr[i].nId == nId )
        {
            return i;
        }
    }

    return -1;
}

TASKDIALOG_BUTTON * QTaskDialog::GetButtonData( const QTaskDialog::QTaskDialogButtonArray & oButtonArr ) const
{
    TASKDIALOG_BUTTON * pResult = nullptr;
    int nCount =  oButtonArr.GetSize() ;

    pResult = new TASKDIALOG_BUTTON[nCount];

    for ( INT_PTR i = 0; i < nCount; i++ )
    {
        pResult[i].nButtonID = oButtonArr[i].nId;
        pResult[i].pszButtonText = oButtonArr[i].strCaption ;
    }

    return pResult;
}

void QTaskDialog::Notify( UINT uMsg,  WPARAM wParam,  LPARAM lParam ) const
{
    if ( m_hWnd != 0 )
    {
        SendMessage( m_hWnd, uMsg, wParam, lParam );
    }
}

INT_PTR QTaskDialog::DoModal( HWND hParent /* = ::GetActiveWindow() */ )
{
    // This option cannot be used after the window has been created.
    ASSERT( nullptr == m_hWnd );


    TASKDIALOGCONFIG configTaskDialog = {0};
    configTaskDialog.hwndParent = hParent;

    FillStruct( configTaskDialog );
    HRESULT nTaskDialogResult = TaskDialogIndirect( &configTaskDialog, &m_nButtonId, &m_nRadioId, &m_bVerified );
    FreeStruct( configTaskDialog );

    if ( S_OK == nTaskDialogResult )
    {
        return static_cast<INT_PTR>( m_nButtonId );
    }
    else
    {
        return -1;
    }
}

HRESULT QTaskDialog::OnInit()
{
    return S_OK;
}

HRESULT QTaskDialog::OnDestroy()
{
    return S_OK;
}

HRESULT QTaskDialog::OnCommandControlClick( int /* nButtonId */ )
{
    return S_OK;
}

HRESULT QTaskDialog::OnRadioButtonClick( int /* nRadioButtonId */ )
{
    return S_OK;
}

HRESULT QTaskDialog::OnVerificationCheckboxClick( BOOL /* bChecked */ )
{
    return S_OK;
}

HRESULT QTaskDialog::OnExpandButtonClick( BOOL /* bExpanded */ )
{
    return S_OK;
}

HRESULT QTaskDialog::OnHyperlinkClick( const QString & strHref )
{
    ShellExecute( m_hWnd, nullptr, strHref, nullptr, nullptr, SW_SHOW );
    return S_OK;
}

HRESULT QTaskDialog::OnHelp()
{
    return S_FALSE;
}

HRESULT QTaskDialog::OnTimer( UINT_PTR id )
{
    return S_OK;
}

HRESULT QTaskDialog::OnNavigatePage()
{
    return S_OK;
}

HRESULT QTaskDialog::OnCreate()
{
    return S_OK;
}
